package funtastic.spellingbee;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import android.app.Application;
import android.content.SharedPreferences;
import android.content.res.AssetManager;
import android.speech.tts.TextToSpeech;
import android.util.Log;

public class SpellingBee extends Application implements TextToSpeech.OnInitListener
{
    private DatabaseHelper             mDatabaseHelper;
    private Document                   mDocumentDefault;
    private String                     mErrorMessage;
    private SharedPreferences          mSharedPreferences;
    private ArrayList<SpellingDetails> mSpellings;
    private TextToSpeech               mTextToSpeech;

    public String addCustomSpelling(String customSpellingList, String customSpellingName, String customSpellingSentence)
    {
        String errorMessage = "";

        int errorCode = mDatabaseHelper.addCustomSpelling(customSpellingList, customSpellingName, customSpellingSentence);
        if (errorCode == DatabaseHelper.ERROR_CODE_NO_ERROR)
        {
            if (getSpellingListType().equals(getString(R.string.list_type_custom)))
            {
                if (getSpellingListName().equals(customSpellingList))
                {
                    setSpellingList(getString(R.string.list_type_custom), customSpellingList);
                }
            }
        }
        else if (errorCode == DatabaseHelper.ERROR_CODE_NOT_UNIQUE)
        {
            errorMessage = "The provided Spelling already exixts. Please enter a unique Spelling.";
        }

        return errorMessage;
    }

    public String addCustomSpellingList(String customSpellingList)
    {
        String errorMessage = "";

        int errorCode = mDatabaseHelper.addCustomSpellingList(customSpellingList);
        if (errorCode == DatabaseHelper.ERROR_CODE_NO_ERROR)
        {
            if (getSpellingListType().equals(getString(R.string.list_type_custom)))
            {
                if (getSpellingListName().trim().length() == 0)
                {
                    String[] spellingLists = getSpellingLists();
                    if (spellingLists.length > 0)
                    {
                        setSpellingList(getString(R.string.list_type_custom), spellingLists[0]);
                    }
                }
            }
        }
        else if (errorCode == DatabaseHelper.ERROR_CODE_NOT_UNIQUE)
        {
            errorMessage = "The provided Spelling List already exixts. Please enter a unique Spelling List.";
        }

        return errorMessage;
    }

    public String deleteCustomSpelling(String customSpellingList, String customSpellingName)
    {
        String errorMessage = "";

        mDatabaseHelper.deleteCustomSpelling(customSpellingList, customSpellingName);

        if (getSpellingListType().equals(getString(R.string.list_type_custom)))
        {
            if (getSpellingListName().equals(customSpellingList))
            {
                setSpellingList(getString(R.string.list_type_custom), customSpellingList);
            }
        }
        
        return errorMessage;
    }

    public String deleteCustomSpellingList(String customSpellingList)
    {
        String errorMessage = "";

        mDatabaseHelper.deleteCustomSpellingList(customSpellingList);
        if (getSpellingListType().equals(getString(R.string.list_type_custom)))
        {
            if (getSpellingListName().equals(customSpellingList))
            {
                String[] spellingLists = getSpellingLists();
                if (spellingLists.length > 0)
                {
                    setSpellingList(getString(R.string.list_type_custom), spellingLists[0]);
                }
            }
        }

        return errorMessage;
    }

    public ArrayList<SpellingDetails> getCustomSpellings(String listName)
    {
        return mDatabaseHelper.getCustomSpellings(listName);
    }

    public String getCustomSpellingSentence(String customSpellingList, String customSpellingName)
    {
        return mDatabaseHelper.getCustomSpellingSentence(customSpellingList, customSpellingName);
    }

    public String getErrorMessage()
    {
        return mErrorMessage;
    }

    public ArrayList<SpellingDetails> getSpellingArrayList()
    {
        return mSpellings;
    }

    public List<SpellingDetails> getSpellingArrayList(int start, int end)
    {
        if (start < 0)
        {
            start = 0;
        }

        if (end > mSpellings.size())
        {
            end = mSpellings.size();
        }

        if (start > end)
        {
            start = end;
        }

        return mSpellings.subList(start, end);
    }

    public String getSpellingListName()
    {
        return mSharedPreferences.getString(getString(R.string.spelling_list_name), "Grade 2");
    }

    public String[] getSpellingLists()
    {
        return getSpellingLists(getSpellingListType());
    }

    public String[] getSpellingLists(String listType)
    {
        String[] spellingListNames;
        if (listType.equals(getString(R.string.list_type_default)))
        {
            if (mDocumentDefault == null)
            {
                spellingListNames = new String[0];
            }
            else
            {
                try
                {
                    Document document = mDocumentDefault;

                    NodeList nodeListSpellingList = document.getElementsByTagName(getString(R.string.spelling_list_name));
                    spellingListNames = new String[nodeListSpellingList.getLength()];
                    for (int i = 0; i < nodeListSpellingList.getLength(); i++)
                    {
                        Element elementSpellingList = (Element) nodeListSpellingList.item(i);
                        spellingListNames[i] = elementSpellingList.getAttribute(getString(R.string.spelling_list_name_name));
                    }
                } catch (Exception e)
                {
                    spellingListNames = new String[0];
                    Log.e(getString(R.string.namespace), e.getMessage(), null);
                }
            }
        }
        else
        {
            spellingListNames = mDatabaseHelper.getCustomSpellingLists();
        }

        return spellingListNames;
    }

    public String getSpellingListType()
    {
        return mSharedPreferences.getString(getString(R.string.spelling_list_type), getString(R.string.list_type_default));
    }

    public TextToSpeech getTextToSpeech()
    {
        return mTextToSpeech;
    }

    public String getTitle()
    {
        return getString(R.string.app_name) + " - " + getSpellingListType() + " - " + getSpellingListName();
    }

    public void initializeTTS()
    {
        mErrorMessage = "";
        mTextToSpeech = new TextToSpeech(this, this);
    }

    @Override
    public void onCreate()
    {
        super.onCreate();

        //this.deleteDatabase(getString(R.string.namespace));
        mDatabaseHelper = new DatabaseHelper(getApplicationContext(), getString(R.string.namespace), Integer.parseInt(getString(R.string.database_version)));
        mDocumentDefault = null;
        mErrorMessage = "";
        mSharedPreferences = getSharedPreferences("SpellingBee", MODE_PRIVATE);

        try
        {
            AssetManager assetManager = getApplicationContext().getAssets();
            InputStream inputStream = assetManager.open("DefaultSpellingList.xml");

            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();

            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();

            mDocumentDefault = documentBuilder.parse(inputStream);
        } catch (Exception e)
        {
            Log.e(getString(R.string.namespace), e.getMessage(), null);
        }

        setSpellingList(getSpellingListType(), getSpellingListName());
    }

    @Override
    public void onInit(int status)
    {
        if (status == TextToSpeech.SUCCESS)
        {
            int result = mTextToSpeech.setLanguage(Locale.US);
            if ((result == TextToSpeech.LANG_MISSING_DATA) || (result == TextToSpeech.LANG_NOT_SUPPORTED))
            {
                mErrorMessage = "TextToSpeech Language Not Found.";
                Log.e(getString(R.string.namespace), mErrorMessage);
            }
            else
            {
                Log.i(getString(R.string.namespace), "TextToSpeech: Initialized Successfully.");
            }
        }
        else
        {
            mErrorMessage = "TextToSpeech Failed Initialization.";
            Log.e(getString(R.string.namespace), mErrorMessage);
        }
    }

    @Override
    public void onTerminate()
    {
        if (mTextToSpeech != null)
        {
            mTextToSpeech.stop();
            mTextToSpeech.shutdown();
        }

        super.onTerminate();
    }

    public void setSpellingList(String listType, String listName)
    {
        SharedPreferences.Editor editor = mSharedPreferences.edit();

        editor.putString(getString(R.string.spelling_list_type), listType);
        editor.putString(getString(R.string.spelling_list_name), listName);
        editor.commit();

        if (listType.equals(getString(R.string.list_type_default)))
        {
            try
            {
                Document document = mDocumentDefault;

                NodeList nodeListSpellingList = document.getElementsByTagName(getString(R.string.spelling_list_name));
                for (int i = 0; i < nodeListSpellingList.getLength(); i++)
                {
                    Element elementSpellingList = (Element) nodeListSpellingList.item(i);
                    if (elementSpellingList.getAttribute(getString(R.string.spelling_list_name_name)).equals(listName))
                    {
                        NodeList nodeListSpelling = elementSpellingList.getElementsByTagName(getString(R.string.spelling));
                        mSpellings = new ArrayList<SpellingDetails>(nodeListSpelling.getLength());
                        for (int j = 0; j < nodeListSpelling.getLength(); j++)
                        {
                            Element elementSpelling = (Element) nodeListSpelling.item(j);
                            mSpellings.add(new SpellingDetails(elementSpelling.getAttribute(getString(R.string.spelling_value)), (elementSpelling.getFirstChild() == null ? "" : elementSpelling.getFirstChild().getNodeValue())));
                        }
                    }
                }
            } catch (Exception e)
            {
                mSpellings = new ArrayList<SpellingDetails>(0);
                throw new RuntimeException(e);
            }
        }
        else
        {
            mSpellings = mDatabaseHelper.getCustomSpellings(listName);
        }
    }

    public String updateCustomSpelling(String customSpellingList, String customSpellingOld, String customSpellingNew, String customSpellingSentence)
    {
        String errorMessage = "";

        int errorCode = mDatabaseHelper.updateCustomSpelling(customSpellingList, customSpellingOld, customSpellingNew, customSpellingSentence);
        if (errorCode == DatabaseHelper.ERROR_CODE_NO_ERROR)
        {
            if (getSpellingListType().equals(getString(R.string.list_type_custom)))
            {
                if (getSpellingListName().equals(customSpellingList))
                {
                    setSpellingList(getString(R.string.list_type_custom), customSpellingList);
                }
            }
        }
        else if (errorCode == DatabaseHelper.ERROR_CODE_NOT_UNIQUE)
        {
            errorMessage = "The provided Spelling already exists. Please enter a unique spelling.";
        }

        return errorMessage;
    }

    public String updateCustomSpellingList(String customSpellingListOld, String customSpellingListNew)
    {
        String errorMessage = "";

        int errorCode = mDatabaseHelper.updateCustomSpellingList(customSpellingListOld, customSpellingListNew);
        if (errorCode == DatabaseHelper.ERROR_CODE_NO_ERROR)
        {
            if (getSpellingListType().equals(getString(R.string.list_type_custom)))
            {
                if (getSpellingListName().equals(customSpellingListOld))
                {
                    setSpellingList(getString(R.string.list_type_custom), customSpellingListNew);
                }
            }
        }
        else if (errorCode == DatabaseHelper.ERROR_CODE_NOT_UNIQUE)
        {
            errorMessage = "The provided Spelling List already exists. Please enter a unique Spelling List Name.";
        }

        return errorMessage;
    }

    public String updateCustomSpellingSentence(String customSpellingList, String customSpelling, String customSpellingSentence)
    {
        String errorMessage = "";

        int errorCode = mDatabaseHelper.updateCustomSpellingSentence(customSpellingList, customSpelling, customSpellingSentence);
        if (errorCode == DatabaseHelper.ERROR_CODE_NO_ERROR)
        {
            if (getSpellingListType().equals(getString(R.string.list_type_custom)))
            {
                if (getSpellingListName().equals(customSpellingList))
                {
                    setSpellingList(getString(R.string.list_type_custom), customSpellingList);
                }
            }
        }
        else if (errorCode == DatabaseHelper.ERROR_CODE_NOT_UNIQUE)
        {
            errorMessage = "The provided Spelling already exixts. Please enter a unique spelling.";
        }

        return errorMessage;
    }

}
